home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d26 / asmtut4.arc / CHAP21.DOC < prev    next >
Text File  |  1990-08-10  |  23KB  |  592 lines

  1.  
  2.  
  3.  
  4.                                                                            219
  5.  
  6.                                 CHAPTER 21 - .COM FILES
  7.  
  8.              All the programs that we have made so far have been .EXE files.
  9.              That means that the file extension has always been .EXE after
  10.              linking. When you have and .EXE file, the program loader makes
  11.              certain adjustments to the machine code at run time. These
  12.              adjustments are the actual segment addresses of the segments. 
  13.  
  14.              There is another type of executable file, and that is a .COM
  15.              file. When the loader puts a .COM file into memory, it makes no
  16.              adjustments, it simply reads the file directly from disk into
  17.              memory. Therefore, a .COM file loads faster. However, there is a
  18.              restriction:
  19.  
  20.                  All code, data, and the stack must be in a single segment.
  21.                  This effectively limits a .COM program to 65536 bytes of
  22.                  code+data+stack. {1}
  23.  
  24.              In general, it is easier for program development to keep code and
  25.              data separate, but we can mix them together. Let's look at the
  26.              template for a .COM file. It is called COMTEMP.ASM.
  27.  
  28.              ; com file template 
  29.              ; put name here 
  30.              ; * * * * * * * * * * * * * * *  
  31.              INCLUDE \PUSHREGS.MAC
  32.               
  33.              COMSEG  SEGMENT  PUBLIC  'CODE' 
  34.  
  35.                     ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG, ss:COMSEG 
  36.              ; - - - - - - - - - -  
  37.              main   proc  NEAR 
  38.  
  39.                     ORG 100h 
  40.              start: 
  41.               
  42.              ; - - - - START CODE BELOW THIS LINE    
  43.               
  44.              ; - - - - END CODE ABOVE THIS LINE    
  45.               
  46.                     ret 
  47.               
  48.              main   endp 
  49.               
  50.              ; - - - - START SUBROUTINES BELOW THIS LINE    
  51.               
  52.              ; - - - - END SUBROUTINES ABOVE THIS LINE    
  53.               
  54.              ____________________
  55.  
  56.                 1. Actually, it is possible to get around this restriction
  57.              with suitable fiddling, but by that time you have made the
  58.              program much more complicated so you have lost any advantage that
  59.              you had by not using an .EXE file.
  60.  
  61.              ______________________
  62.  
  63.              The PC Assembler Tutor - Copyright (C) 1989 Chuck Nelson
  64.  
  65.  
  66.  
  67.  
  68.              The PC Assembler Tutor                                        220
  69.              ______________________
  70.  
  71.               
  72.              ; - - - - START DATA BELOW THIS LINE    
  73.               
  74.              ; - - - - END DATA ABOVE THIS LINE    
  75.  
  76.              Stack_area  dw  500 dup (?)
  77.               
  78.              COMSEG ENDS 
  79.              ; * * * * * * * * * * * * * * * 
  80.              END  start 
  81.  
  82.              We will take the things in order. First, there is the line:
  83.  
  84.                  ORG  100h
  85.  
  86.              This effectively tells the assembler to put 100h (256d) bytes of
  87.              zeros at the beginning. Also notice that the setup code that we
  88.              had in a .EXE file is missing; we start with the code
  89.              immediately. This all has to do with the PSP (program segment
  90.              prefix).{2}
  91.  
  92.  
  93.              PSP
  94.  
  95.              You will remember from the chapter describing the .EXE template
  96.              file that we wrote:
  97.  
  98.                  push ds
  99.                  sub  ax, ax
  100.                  push ax
  101.  
  102.              because upon entry to an .EXE file, DS contains the segment
  103.              address of the PSP, and at offset 0000 (that is, the first byte
  104.              of the segment) there is a machine instruction for an orderly
  105.              exit from the program. In an .EXE file, the PSP is somewhere in
  106.              memory, put there by the loader. In a .COM file, the PSP is the
  107.              first 100h (256d) bytes of the segment. The loader fills in the
  108.              PSP and then reads the file directly from disk. That means that
  109.              the machine instruction for an orderly exit is at 0000 of the
  110.              current segment. Notice that we have a NEAR procedure. A .COM
  111.              file has a near return which will stay in the same segment.
  112.              Normally we would have to write:
  113.  
  114.                  sub  ax, ax
  115.                  push ax
  116.  
  117.              to put the return address 0000 on the stack, but for a .COM file
  118.              the loader pushes 0000 on the stack before giving control to the
  119.              program. Why the loader provides this service for a .COM file but
  120.              not for an .EXE file is a mystery. In any case, with a .COM file,
  121.              you don't need to push the return address on the stack, since
  122.              it's there already.
  123.              ____________________
  124.  
  125.                 2. If you want to know what the PSP (program segment prefix)
  126.              is exactly, consult either of the two books on hardware and
  127.              interrupts. The PSP is always exactly 256 bytes long.
  128.  
  129.  
  130.  
  131.  
  132.              Chapter 21 - .COM Files                                       221
  133.              _______________________
  134.  
  135.  
  136.              We have the assembler directive:
  137.  
  138.                     ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG, ss:COMSEG 
  139.  
  140.              The reason for including all the segments is (1) the loader
  141.              actually loads the segment address into all four segments and (2)
  142.              the assembler will use the natural segment for all instructions.
  143.              The BP instructions will refer to SS, the data instructions will
  144.              refer to DS, the string move instructions (SCAS, CMPS, MOVS) will
  145.              refer to ES. That means that the assembler will not use segment
  146.              overrides. This helps avoid something called phase errors which
  147.              will be explained at the end.
  148.  
  149.  
  150.              Right after the ORG instruction is start: (the first instruction
  151.              executed in the program.)
  152.  
  153.                       ORG 100h       ; 256d
  154.                  start:
  155.  
  156.              This is inflexible. After reading the program into memory, the
  157.              loader ALWAYS starts the program at 100h. All .COM files start
  158.              execution at 100h. Period.
  159.  
  160.              There is space for subroutines, space for data, and finally space
  161.              for the stack. The order of subroutines and data can be changed.
  162.              The stack space is technically not necessary, but it is a good
  163.              reminder to leave it there. All .COM files take up a whole 65536
  164.              byte segment in memory, no matter how short they are.{3} The
  165.              stack is at the very end of the segment, so if your program is
  166.              200 bytes long, you have 65336 bytes of stack space.
  167.  
  168.              Let's make a simple program. It is the famous "Hello,World"
  169.              program.
  170.  
  171.              ; - - - - START CODE BELOW THIS LINE    
  172.                  mov  dx, offset mr_happy_face      ; int 21h, function 9
  173.                  mov  ah, 9
  174.                  int  21h 
  175.              ; - - - - END CODE ABOVE THIS LINE    
  176.               
  177.              ; - - - - START DATA BELOW THIS LINE    
  178.              mr_happy_face db  "Hello, world!", 13, 10, "$"
  179.              ; - - - - END DATA ABOVE THIS LINE  
  180.  
  181.              This program prints 'Hello World!' and a new line. The dollar
  182.              sign signifies the end of the string for this interrupt. It is
  183.              simple enough, and it gives us the chance to look at the extra
  184.              step needed to make a .COM file. Assemble it, and link it. When
  185.              you link it, you will get a warning that there is no stack
  186.              segment. For .COM files, this warning is unimportant. We now have
  187.              an .EXE file (which, by the way, won't run correctly). How do we
  188.              ____________________
  189.  
  190.                 3. This is a slightly abridged explaination. For the real
  191.              details, consult Microsoft's "The MS-DOS Encyclopedia".
  192.  
  193.  
  194.  
  195.  
  196.              The PC Assembler Tutor                                        222
  197.              ______________________
  198.  
  199.              make it a .COM file?
  200.  
  201.              Among the programs that you got with DOS is one called EXE2BIN.
  202.              It takes an .EXE file, and if possible, converts it into a .COM
  203.              file. You simply write the name of the file you want converted
  204.              and the name of the converted file. Both of these names must have
  205.              the full file extension:
  206.  
  207.                  exe2bin  programA.exe  programA.com
  208.  
  209.              You will now have programA.com as a .COM file. If we now write:
  210.  
  211.                  C> programA
  212.  
  213.              Will the loader load the .COM file or the .EXE file? The DOS
  214.              order for execution is .COM files first, then .EXE files, then
  215.              .BAT files. DOS will execute the .COM file. Try it.
  216.  
  217.              That was pretty easy. Now, as a technical exercise, we  are going
  218.              to link together three different files. Here's the first file:
  219.  
  220.                  ; prog1.asm 
  221.                  ; * * * * * * * * * * * * * * *  
  222.                  INCLUDE \PUSHREGS.MAC
  223.                  COMSEG  SEGMENT  PUBLIC  'CODE' 
  224.               
  225.                         ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG, ss:COMSEG 
  226.               
  227.                  PUBLIC message1 
  228.                  EXTRN  subroutine_a:NEAR, message3:BYTE 
  229.                  ; - - - - - - - - - -  
  230.                  main   proc  NEAR 
  231.               
  232.                         ORG 100h 
  233.                  start: 
  234.                         mov   ah, 9                ; int 21h, ah = 9 
  235.                         mov   dx, offset message1 
  236.                         int   21h 
  237.               
  238.                         mov   ah, 9                ; int 21h, ah = 9 
  239.                         mov   dx, offset message3 
  240.                         int   21h 
  241.                   
  242.                         call  subroutine_a 
  243.                         ret 
  244.               
  245.                  main   endp 
  246.               
  247.                  message1 db  "This is from the main program.", 13, 10, "$" 
  248.               
  249.                  COMSEG ENDS 
  250.                  ; * * * * * * * * * * * * * * * 
  251.                  END  start 
  252.                  ; ----------
  253.  
  254.              Here is the second file:
  255.                  ; prog2.asm 
  256.  
  257.  
  258.  
  259.  
  260.              Chapter 21 - .COM Files                                       223
  261.              _______________________
  262.  
  263.                  ; * * * * * * * * * * * * * * *  
  264.                  INCLUDE \PUSHREGS.MAC
  265.                  COMSEG  SEGMENT  PUBLIC  'CODE' 
  266.               
  267.                         ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG, ss:COMSEG 
  268.               
  269.                  PUBLIC message2, subroutine_a 
  270.                  EXTRN  subroutine_b:NEAR, message3:BYTE 
  271.                  ; - - - - - - - - - -  
  272.                  subroutine_a   proc  NEAR 
  273.               
  274.                         PUSHREGS ax, dx
  275.                         mov   ah, 9                ; int 21h, ah = 9 
  276.                         mov   dx, offset message2 
  277.                         int   21h 
  278.  
  279.                         mov   ah, 9                ; int 21h, ah = 9 
  280.                         mov   dx, offset message3 
  281.                         int   21h 
  282.               
  283.                         call  subroutine_b 
  284.                         POPREGS ax, dx
  285.                         ret 
  286.               
  287.                  subroutine_a   endp 
  288.               
  289.                  message2 db  "This is from subroutine A.", 13, 10, "$" 
  290.               
  291.                  COMSEG ENDS 
  292.                  ; * * * * * * * * * * * * * * * 
  293.                  END  
  294.                  ; ----------
  295.  
  296.              And here is the third file:
  297.  
  298.                  ; prog3.asm 
  299.                  ; * * * * * * * * * * * * * * *  
  300.                  INCLUDE \PUSHREGS.MAC
  301.                  COMSEG  SEGMENT  PUBLIC  'CODE' 
  302.               
  303.                         ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG, ss:COMSEG 
  304.               
  305.                  PUBLIC message3, subroutine_b 
  306.                  EXTRN  message1:BYTE, message2:BYTE 
  307.                  ; - - - - - - - - - -  
  308.                  subroutine_b   proc  NEAR 
  309.               
  310.                         PUSHREGS ax, dx
  311.                         mov   ah, 9                ; int 21h, ah = 9 
  312.                         mov   dx, offset message1 
  313.                         int   21h 
  314.               
  315.                         mov   ah, 9                ; int 21h, ah = 9 
  316.                         mov   dx, offset message2 
  317.                         int   21h 
  318.  
  319.                         POPREGS ax, dx
  320.  
  321.  
  322.  
  323.  
  324.              The PC Assembler Tutor                                        224
  325.              ______________________
  326.  
  327.                         ret 
  328.               
  329.                  subroutine_b   endp 
  330.               
  331.                  message3 db  "This is from subroutine B.", 13, 10, "$" 
  332.               
  333.                  COMSEG ENDS 
  334.                  ; * * * * * * * * * * * * * * * 
  335.                  END  
  336.                  ; ----------
  337.  
  338.              If you look at them, you will see that all they do is print
  339.              messages; sometimes from their own file, sometimes from external
  340.              files. The subprograms all have different names since they call
  341.              each other. Of course, they have both PUBLIC and EXTRN
  342.              statements. Only prog1 has:
  343.  
  344.                  start:
  345.  
  346.              since that is where the program execution will start, and only
  347.              prog1 has:
  348.  
  349.                   ORG 100h
  350.  
  351.              since having it in the other files would leave unnecessary blank
  352.              spaces in the other programs. Assemble the programs. When you
  353.              link the programs, prog1 MUST be the first on the line:
  354.  
  355.                  link prog1+prog2+prog3
  356.                  link prog1+prog3+prog2
  357.  
  358.              are both ok, but:
  359.  
  360.                  link prog2+prog1+prog3
  361.  
  362.              will not work since the linker, exe2bin, and the loader are
  363.              counting on the starting instruction being at 100h. If you change
  364.              the order, you will either get complaints from EXE2BIN or the
  365.              program won't run correctly. Now with:
  366.  
  367.                  exe2bin  prog1.exe  prog1.com
  368.  
  369.              you have a .COM file. Try it out.
  370.  
  371.  
  372.              Any .COM file can also be made into an .EXE file. We will make a
  373.              simple program in .COM format, and then add the necessary things
  374.              to make it an .EXE format. First, here's the .COM format.
  375.  
  376.  
  377.              ; commode.asm 
  378.              ; * * * * * * * * * * * * * * *  
  379.              COMSEG  SEGMENT  PUBLIC  'CODE' 
  380.               
  381.                     ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG, ss:COMSEG 
  382.               
  383.              main   proc  NEAR 
  384.  
  385.  
  386.  
  387.  
  388.              Chapter 21 - .COM Files                                       225
  389.              _______________________
  390.  
  391.               
  392.                     ORG 100h 
  393.              start: 
  394.                     ; get video mode int 10h, function 0Fh 
  395.                     mov   ah, 0Fh
  396.                     int   10h 
  397.               
  398.                     ; al = display mode 
  399.                     mov   bl, 10              ; divide by 10 
  400.                     mov   si, offset ones     ; right hand digit 
  401.                     mov   cx, 2               ; 2 digit answer 
  402.              division_loop: 
  403.                     mov   ah, 0               ; clear ah 
  404.                     div   bl                  ; al/bl, remainder in ah 
  405.                     add   ah, '0'             ; change to ascii 
  406.                     mov   [si], ah 
  407.                     dec   si                  ; one byte to the left 
  408.                     loop  division_loop 
  409.               
  410.                     ; display string 
  411.                     mov   dx, offset message  ; int 21h, service 9 
  412.                     mov   ah, 9 
  413.                     int   21h 
  414.               
  415.                     ret 
  416.               
  417.              main   endp 
  418.               
  419.              ; - - - - START DATA BELOW THIS LINE    
  420.              message      db  "The  current video mode is  " 
  421.              ones         db  ? 
  422.                           db  ".",  13, 10, "$" 
  423.              ; - - - - END DATA ABOVE THIS LINE    
  424.               
  425.              COMSEG ENDS 
  426.              ; * * * * * * * * * * * * * * * 
  427.              END  start 
  428.              ; - - - - - - - - - - 
  429.  
  430.              This program gets the video mode which is a number which tells
  431.              you what mode the monitor is operating in. To find out what the
  432.              number means, consult either of those two hardware books. It gets
  433.              the mode through an interrupt. The mode is returned in AL. It
  434.              then puts the number in a string and prints the string. We cannot
  435.              link with asmhelp.obj, so it takes all this work is simply to
  436.              output a number.
  437.  
  438.              We'll call this commode.asm. Assemble, link, use exe2bin, and run
  439.              it. Now let's make the .EXE counterpart. Here it is.
  440.  
  441.              ; exemode.asm 
  442.              ; * * * * * * * * * * * * * * *  
  443.              STACKSEG     SEGMENT  STACK  'STACK' 
  444.               
  445.                     dw    20 dup (?) 
  446.               
  447.              STACKSEG  ENDS 
  448.  
  449.  
  450.  
  451.  
  452.              The PC Assembler Tutor                                        226
  453.              ______________________
  454.  
  455.              ; - - - - - - - - - - 
  456.              COMSEG  SEGMENT  PUBLIC  'CODE' 
  457.               
  458.                     ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG 
  459.               
  460.              main   proc  FAR 
  461.               
  462.              start: 
  463.                     push  ds                  ; same as before 
  464.                     sub   ax, ax 
  465.                     push  ax 
  466.               
  467.                     push  cs                  ; ds = cs 
  468.                     pop   ds 
  469.               
  470.                     ; get video mode int 10h, service 15 
  471.                     mov   ah, 15 
  472.                     int 10h 
  473.               
  474.                     ; al = display mode 
  475.                     mov   bl, 10              ; divide by 10 
  476.                     mov   si, offset ones     ; right hand digit 
  477.                     mov   cx, 2               ; 2 digit answer 
  478.              division_loop: 
  479.                     mov   ah, 0               ; clear ah 
  480.                     div   bl                  ; al/bl, remainder in ah 
  481.                     add   ah, '0'             ; change to ascii 
  482.                     mov   [si], ah 
  483.                     dec   si                  ; one byte to the left 
  484.                     loop  division_loop 
  485.               
  486.                     ; display string 
  487.                     mov   dx, offset message  ; int 21h, service 9 
  488.                     mov   ah, 9 
  489.                     int   21h 
  490.               
  491.                     ret 
  492.               
  493.              main   endp 
  494.               
  495.              ; - - - - START DATA BELOW THIS LINE    
  496.              message      db  "The  current video mode is  " 
  497.              ones         db  ? 
  498.                           db  ".",  13, 10, "$" 
  499.              ; - - - - END DATA ABOVE THIS LINE    
  500.               
  501.              COMSEG ENDS 
  502.              ; * * * * * * * * * * * * * * * 
  503.              END  start 
  504.  
  505.              This is almost the same. We have put in a small stack segment.
  506.              Here's the different part:
  507.  
  508.              ;----------
  509.                     ASSUME  cs:COMSEG, ds:COMSEG, es:COMSEG 
  510.               
  511.              main   proc  FAR 
  512.  
  513.  
  514.  
  515.  
  516.              Chapter 21 - .COM Files                                       227
  517.              _______________________
  518.  
  519.               
  520.              start: 
  521.                     push  ds                  ; same as before 
  522.                     sub   ax, ax 
  523.                     push  ax 
  524.               
  525.                     push  cs                  ; ds = cs 
  526.                     pop   ds 
  527.  
  528.              ;----------
  529.  
  530.              SS is no longer in the ASSUME statement, since it now refers to
  531.              the stack segment. CS, DS, and ES still refer to COMSEG. The
  532.              procedure is now a FAR procedure. We have taken the ORG out,
  533.              since that would simply waste 100h (256) bytes of space. Then we
  534.              have the normal .EXE startup except the data is now in COMSEG, so
  535.              we move CS to DS. That's it. We'll call this one exemode.asm.
  536.              Assemble, link and run it. It should give you the same result. 
  537.  
  538.              Here is the listing for both executable files:
  539.  
  540.                  COMMODE  COM       65  10-21-89  11:11p
  541.                  EXEMODE  EXE      631  10-21-89  11:10p
  542.  
  543.              Notice how much bigger the .EXE file is. That is because the .EXE
  544.              file has a bunch of information for the loader. Also, if you run
  545.              both programs, the .COM file will start a little quicker. Those
  546.              are the only advantages.
  547.  
  548.  
  549.              PHASE ERRORS
  550.  
  551.              The assembler generates code in two steps. On the first pass, it
  552.              calculates the address of each variable and machine instruction
  553.              without actually writing code. For instance, if there is the
  554.              instruction:
  555.  
  556.                  mov  ax, variable1
  557.  
  558.              The assembler will allocate 4 bytes for the instruction. If
  559.              variable1 has already been defined, but is in ES, then the
  560.              assembler will allocate 5 bytes; 1 for the segment override and 4
  561.              for the instruction itself. If, however, variable1 has not been
  562.              defined yet (it appears later in the code), then the assembler
  563.              will assume that it is in DS and allocate 4 bytes. If it turns
  564.              out that it is later defined to be in ES, then when the assembler
  565.              generates code, it will write 5 bytes, 1 for the override and 4
  566.              for the instruction. But this means that EVERYTHING after this
  567.              instruction will have been shifted one byte, so EVERYTHING after
  568.              the instruction will be at the wrong address. The assembler will
  569.              detect this and print out a PHASE ERROR. This means that the
  570.              machine code is garbage.
  571.  
  572.              By having all four segment registers in the ASSUME statement of a
  573.              .COM file, you guarantee that the assembler will not generate
  574.              segment overrides.
  575.  
  576.  
  577.  
  578.  
  579.  
  580.              The PC Assembler Tutor                                        228
  581.              ______________________
  582.  
  583.                  add  dx, [bp]
  584.  
  585.              will have BP relative to SS.
  586.  
  587.                  sub  variable1, si
  588.  
  589.              will have variable1 relative to DS. This will go a long way
  590.              towards eliminating errors in a .COM file.
  591.  
  592.